﻿/*======================================
作者：洞庭夕照
创建：2017.8.21
网站：www.ninesky.cn
      mzwhj.cnblogs.com
代码：git.oschina.net/ninesky/Ninesky
版本：v1.0.0.0
======================================*/
using Microsoft.EntityFrameworkCore;
using Ninesky.IService;
using Ninesky.Models;
using System.Linq;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Linq.Expressions;
using System;
using Ninesky.DBLibrary;


namespace Ninesky.Service
{
    /// <summary>
    /// 栏目服务
    /// </summary>
    public class CategoryService:BaseService<Category>,ICategoryService
    {
        public CategoryService(NsDbContext nsDbContext):base(nsDbContext)
        {
            
        }

        /// <summary>
        /// 添加栏目
        /// </summary>
        /// <param name="entity">实体</param>
        /// <param name="isSave">是否立即保存[可选]</param>
        /// <returns>操作结果
        /// OperationResult.Succeed：操作是否完成，当isSave=false仅表示操作完成并未实际保存到数据库；
        /// OperationResult.Code：当OperationResult.Succeed为false时：1-数据验证失败；
        /// OperationResult.Message：操作结果的文本提示；
        /// OperationResult.Data：当Code=1时返回类型Dictionary<string, string>，第一个string表示属性，第二个string表示错误提示。
        /// </returns>
        public override async Task<OperationResult> AddAsync(Category entity, bool isSave = true)
        {
            Dictionary<string, string> errors = new Dictionary<string, string>();
            //设置默认值
            entity.ChildNum = 0;
            OperationResult opsResult = new OperationResult() { Succeed = true };
            //检查父栏目
            if (entity.ParentId > 0)
            {
                var parentCategory = await FindAsync(entity.ParentId);
                if (parentCategory == null)
                {
                    opsResult.Succeed = false;
                    opsResult.Message = "父栏目不存在";
                }
                else if (parentCategory.Type != CategoryType.General)
                {
                    opsResult.Succeed = false;
                    opsResult.Message = "父栏目不是常规栏目";
                }
                else
                {
                    entity.ParentPath = parentCategory.ParentPath + "," + parentCategory.CategoryId;
                    entity.Depth = parentCategory.Depth + 1;
                    parentCategory.ChildNum++;
                    await UpdateAsync(parentCategory, false);
                }
            }
            //父栏目为0
            else
            {
                entity.ParentPath = "0";
                entity.Depth = 1;
            }//检查父栏目结束
            switch(entity.Type)
            {
                case CategoryType.General:
                    if(string.IsNullOrEmpty(entity.View)) errors.Add("View", "栏目视图必填");
                    if(Enum.IsDefined(typeof(ModuleType), entity.ModuleType))
                    {
                        if(string.IsNullOrEmpty(entity.ContentView)) errors.Add("ContentView", "内容视图必填");
                        if(entity.ContentOrder == null) errors.Add("ContentOrder", "内容排序必填");
                        if (entity.PageSize == null) errors.Add("PageSize", "每页记录数必填");
                        else if (entity.PageSize < 1) errors.Add("PageSize", "每页记录数必须大于0");
                    }
                    break;
                case CategoryType.Page:
                    if (string.IsNullOrEmpty(entity.View)) errors.Add("View", "栏目视图必填");
                    break;
                case CategoryType.Link:
                    if (string.IsNullOrEmpty(entity.LinkUrl)) errors.Add("LinkUrl", "链接地址必填");
                    break;
            }
            if (errors.Count() > 0)
            {
                opsResult.Succeed = false;
                opsResult.Code = 1;
                opsResult.Message = "数据验证失败";
                opsResult.Data = errors;
            }
            if (opsResult.Succeed) opsResult = await base.AddAsync(entity, isSave);
            return opsResult;
        }
        
        /// <summary>
        /// 查找子栏目
        /// </summary>
        /// <param name="id">栏目Id</param>
        /// <returns>子栏目列表</returns>
        public async Task<IQueryable<Category>> FindChildrenAsync(int id)
        {
            return await FindListAsync<int>(0, c => c.ParentId == id, c => c.Order, true);
        }

        /// <summary>
        /// 查找栏目列表
        /// </summary>
        /// <param name="predicate">查询表达式</param>
        /// <returns>栏目列表</returns>
        public async Task<IQueryable<Category>> FindListAsync(Expression<Func<Category, bool>> predicate)
        {
            return await FindListAsync<int>(0, predicate, c => c.CategoryId, true);
        }

        /// <summary>
        /// 查找栏目
        /// </summary>
        /// <param name="cType">栏目类型[0-未设置]</param>
        /// <param name="mType">内容类型[0-未设置]</param>
        /// <param name="inclParent">是否包含父栏目</param>
        /// <returns>栏目列表</returns>
        public async Task<IQueryable<Category>> FindListAsync(CategoryType cType, ModuleType mType, bool inclParent)
        {
            //栏目集合
            IQueryable<Category> categories = await FindAllAsync();
            if (Enum.IsDefined(typeof(CategoryType),cType)) categories = categories.Where(c => c.Type == cType);
            if (Enum.IsDefined(typeof(ModuleType),mType)) categories = categories.Where(c => c.ModuleType == mType);

            if (inclParent)
            {
                //栏目Id列表
                var catgIdList = categories.Select(c => c.CategoryId).ToList();
                //栏目Id列表字符串表示形式
                List<string> strCatgIdList = new List<string>();
                //父栏目路径列表
                var catgParPathLisst = categories.Select(c => c.ParentPath).ToList();
                //将父栏目路径分割成栏目id字符串并添加到strCatgIdList
                foreach (var catgParPath in catgParPathLisst)
                {
                    strCatgIdList.AddRange(catgParPath.Split(',', StringSplitOptions.RemoveEmptyEntries));
                }
                //栏目id
                int catgId = 0;
                foreach (var strParId in strCatgIdList)
                {
                    if (int.TryParse(strParId, out catgId) && !catgIdList.Contains(catgId)) catgIdList.Add(catgId);
                }
                categories = categories.Where(c => catgIdList.Contains(c.CategoryId));
            }

            return categories;
        }
        /// <summary>
        /// 更新实体
        /// </summary>
        /// <param name="entity">实体</param>
        /// <param name="isSave">是否立即保存</param>
        /// <returns>操作结果
        /// OperationResult.Succeed：操作是否完成，当isSave=false仅表示操作完成并未实际保存到数据库；
        /// OperationResult.Code：当OperationResult.Succeed为false时：1-数据验证失败；2-栏目不存在
        /// OperationResult.Message：操作结果的文本提示；
        /// OperationResult.Data：当Code=1时返回类型Dictionary<string, string>，第一个string表示属性，第二个string表示错误提示。
        /// </returns>
        public override async Task<OperationResult> UpdateAsync(Category entity, bool isSave = true)
        {
            //模型验证错误列表
            Dictionary<string, string> errors = new Dictionary<string, string>();  
            var opsResult = new OperationResult() { Succeed = true, Message = "更新成功栏目" };
            var originalCategory = await  FindAsync(entity.CategoryId);
            //验证栏目
            if(originalCategory == null)
            {
                opsResult.Succeed = false;
                opsResult.Code = 2;
                opsResult.Message = "栏目不存在";
                return opsResult;
            }
            //验证栏目类型
            else if(originalCategory.Type != entity.Type) errors.Add("Type", "禁止修改栏目类型");
            
            //验证父栏目
            if (entity.ParentId != 0)
            {
                var parentCategory = await FindAsync(c => c.CategoryId == entity.ParentId);
                if (parentCategory == null) errors.Add("ParentId", "父栏目不存在");
                else if (parentCategory.CategoryId == originalCategory.CategoryId) errors.Add("ParentId", "父栏目不能是其本身");
                else if (parentCategory.Type != CategoryType.General) errors.Add("ParentId", "只有常规栏目才能作为父栏目");
                else if (parentCategory.ParentPath.Split(',', System.StringSplitOptions.RemoveEmptyEntries).Contains(originalCategory.CategoryId.ToString())) errors.Add("ParentId", "父栏目不能是当前栏目的子栏目");
            }
            //验证其他项
            switch (entity.Type)
            {
                //常规栏目
                case CategoryType.General:
                    if (string.IsNullOrEmpty(entity.View)) errors.Add("View", "栏目视图必填");
                    if (Enum.IsDefined(typeof(ModuleType), entity.ModuleType))
                    {
                        if (string.IsNullOrEmpty(entity.ContentView)) errors.Add("ContentView", "内容视图必填");
                        if (entity.ContentOrder == null) errors.Add("ContentOrder", "内容排序必填");
                        if (entity.PageSize == null) errors.Add("PageSize", "每页记录数必填");
                        else if (entity.PageSize < 1) errors.Add("PageSize", "每页记录数必须大于0");
                    }
                    break;
                    //单页栏目
                case CategoryType.Page:
                    if (string.IsNullOrEmpty(entity.View)) errors.Add("View", "栏目视图必填");
                    break;
                    //链接栏目
                case CategoryType.Link:
                    if (string.IsNullOrEmpty(entity.LinkUrl)) errors.Add("LinkUrl", "链接地址必填");
                    break;
            }
            //数据验证是否通过
            if (errors.Count() == 0)
            {
                //父栏目发生更改
                if (entity.ParentId != originalCategory.ParentId)
                {
                    //新父栏目为0
                    if (entity.ParentId == 0)
                    {
                        //更改原来父栏目的子栏目数
                        var originalParent = await FindAsync(originalCategory.ParentId);
                        if (originalParent != null)
                        {
                            originalParent.ChildNum--;
                            await base.UpdateAsync(originalParent, false);
                        }
                        //处理子栏目
                        if (originalCategory.ChildNum > 0)
                        {
                            var childrenCategories = await FindListAsync<string>(0, c => c.ParentPath.IndexOf(originalCategory.ParentPath+","+originalCategory.CategoryId) == 0, c => c.ParentPath, true);
                            foreach (var childCategory in childrenCategories)
                            {
                                childCategory.ParentPath = childCategory.ParentPath.Replace(originalCategory.ParentPath + "," + originalCategory.CategoryId, "0," + originalCategory.CategoryId);
                                childCategory.Depth = childCategory.Depth - originalCategory.Depth + 1;
                            }
                            NsDbContext.Set<Category>().UpdateRange(childrenCategories.ToArray());
                        }
                        originalCategory.ParentId = entity.ParentId;
                        originalCategory.ParentPath = "0";
                        originalCategory.Depth = 1;
                    }
                    else
                    {
                        var parentCategory = await FindAsync(c => c.CategoryId == entity.ParentId);
                        entity.ParentPath = parentCategory.ParentPath + "," + entity.CategoryId;
                        entity.Depth = parentCategory.Depth + 1;
                        if (originalCategory.ParentId != 0)
                        {
                            //更改原来父栏目的子栏目数
                            var originalParent = await FindAsync(originalCategory.ParentId);
                            if (originalParent != null)
                            {
                                originalParent.ChildNum--;
                                await base.UpdateAsync(originalParent, false);
                            }
                            //处理子栏目
                            if (originalCategory.ChildNum > 0)
                            {
                                var childrenCategories = await FindListAsync<string>(0, c => c.ParentPath.IndexOf(originalCategory.ParentPath + "," + originalCategory.CategoryId) == 0, c => c.ParentPath, true);
                                foreach (var childCategory in childrenCategories)
                                {
                                    childCategory.ParentPath = childCategory.ParentPath.Replace(originalCategory.ParentPath + "," + originalCategory.CategoryId, entity.ParentPath + "," + originalCategory.CategoryId);
                                    childCategory.Depth = childCategory.Depth - originalCategory.Depth + 1;
                                }
                                NsDbContext.Set<Category>().UpdateRange(childrenCategories.ToArray());
                            }
                        }
                        //处理子栏目
                        if (originalCategory.ChildNum > 0)
                        {
                            var childrenCategories = await FindListAsync<string>(0, c => c.ParentPath.IndexOf(originalCategory.ParentPath + "," + originalCategory.CategoryId) == 0, c => c.ParentPath, true);
                            foreach (var childCategory in childrenCategories)
                            {
                                childCategory.ParentPath = childCategory.ParentPath.Replace(originalCategory.ParentPath + "," + originalCategory.CategoryId, parentCategory.ParentPath + "," + originalCategory.CategoryId);
                                childCategory.Depth = childCategory.Depth - originalCategory.Depth + entity.Depth;
                            }
                            NsDbContext.Set<Category>().UpdateRange(childrenCategories.ToArray());
                        }
                        originalCategory.ParentId = entity.ParentId;
                        originalCategory.ParentPath = entity.ParentPath;
                        originalCategory.Depth = entity.Depth;
                    }
                }


                if (originalCategory.Name != entity.Name) originalCategory.Name = entity.Name;
                if (originalCategory.PicUrl != entity.PicUrl) originalCategory.PicUrl = entity.PicUrl;
                if (originalCategory.Meta_Keywords != entity.Meta_Keywords) originalCategory.Meta_Keywords = entity.Meta_Keywords;
                if (originalCategory.Meta_Description != entity.Meta_Description) originalCategory.Meta_Description = entity.Meta_Description;
                if (originalCategory.Description != entity.Description) originalCategory.Description = entity.Description;
                if (originalCategory.Target != entity.Target) originalCategory.Target = entity.Target;
                if (originalCategory.Order != entity.Order) originalCategory.Order = entity.Order;
                if (originalCategory.View != entity.View) originalCategory.View = entity.View;
                if (originalCategory.ModuleType != entity.ModuleType) originalCategory.ModuleType = entity.ModuleType;
                if (originalCategory.ContentView != entity.ContentView) originalCategory.ContentView = entity.ContentView;
                if (originalCategory.ContentOrder!= entity.ContentOrder) originalCategory.ContentOrder = entity.ContentOrder;
                if (originalCategory.PageSize != entity.PageSize) originalCategory.PageSize = entity.PageSize;
                if (originalCategory.ShowOnMenu != entity.ShowOnMenu) originalCategory.ShowOnMenu = entity.ShowOnMenu;
                if (originalCategory.LinkUrl != entity.LinkUrl) originalCategory.LinkUrl = entity.LinkUrl;
            }
            else
            {
                opsResult.Succeed = false;
                opsResult.Code = 1;
                opsResult.Message = "数据验证失败";
                opsResult.Data = errors;
            }
            //更新数据
            if (opsResult.Succeed)
            {
                opsResult = await base.UpdateAsync(originalCategory, isSave);
            }

            return opsResult;
        }

        public override async Task<OperationResult> RemoveAsync(Category entity, bool isSave = true)
        {
            OperationResult opsResult = new OperationResult();
            Category category = await FindAsync(entity.CategoryId);
            if (category == null) return new OperationResult() { Succeed = false, Message = "栏目不存在" };
            else if (category.Type == CategoryType.General)
            {
                if (category.ChildNum > 0) return new OperationResult() { Succeed = false, Message = "请先删除子栏目" };
                //此处应检查是否有内容
            }
            else
            {
                ContentService contentService = new ContentService(NsDbContext);
                if(await contentService.ExistsAsync(c=>c.CategoryId == entity.CategoryId)) return new OperationResult() { Succeed = false, Message = "请先删除栏目内容" };
            }
            int parentId = category.ParentId;
            //父栏目中的子栏目数目减1
            if (parentId > 0)
            {
                var parent = await FindAsync(parentId);
                if (parent != null)
                {
                    parent.ChildNum--;
                    await UpdateAsync(parent, false);
                }
            }
            opsResult = await base.RemoveAsync(category, isSave);
            return opsResult;
        }
    }
}
